package com.xt.base.reflection;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Apply {
	
	private Apply(){}
	
	/***
	 *被迭代的数组元素作为执行目标迭代执行某方法，返回执行结果的数组
	 *@param seq  被迭代的数组
	 *@param f 执行的方法
	 *@param v 返回值数组，当该数组的长度不够时，返回该类型的新的数组
	 *@param args 方法执行的参数表
	 *@return 执行结果数组，类型为参数v的类型。
	 ****/
	@SuppressWarnings("unchecked")
	public static <T,V> V[] apply(T[] seq,Method f,V[] v,Object... args){
		try{
			if(seq == null)return null;
			int size = seq.length;
	        if (v.length < size)v = (V[])java.lang.reflect.Array.
				newInstance(v.getClass().getComponentType(), size);
			for(int i=0;i<seq.length;i++)v[i] = (V)f.invoke(seq[i], args);
			return v;
		}catch(Exception e){
			throw new RuntimeException(e);
		}
	}

	/***
	 *被迭代的数组元素作为参数的一部分迭代执行某方法，返回执行结果的数组
	 *@param seq  被迭代的数组
	 *@param f 执行的方法
	 *@param target 执行方法的对象
	 *@param v 返回值数组，当该数组的长度不够时，返回该类型的新的数组
	 *@param pos 被迭代的数组元素在参数表中的位置
	 *@param args 方法执行的参数表
	 *@return 执行结果数组，类型为参数v的类型。
	 ****/
	@SuppressWarnings("unchecked")
	public static <T,V> V[] each(T[] seq,Method f,Object target,V[] v,int pos,Object... args){
		try{
			if(seq == null)return null;
			Object[] newArgs = parseArgs(args,pos);
			int size = seq.length;
	        if (v.length < size)v = (V[])java.lang.reflect.Array.
				newInstance(v.getClass().getComponentType(), size);
			for(int i=0;i<seq.length;i++){
				newArgs[pos] = seq[i];
				v[i] = (V)f.invoke(target, newArgs);
			}
			return v;
		}catch(Exception e){
			throw new RuntimeException(e);
		}
	}
	
	private static Object[] parseArgs(Object[] args,int pos){
		if(pos < 0 || pos > args.length)
			throw new RuntimeException("Error parameter in Apply.each:args insert position error.");
        Object[] newArgs = new Object[args.length + 1];
        if(pos > 0 )
        	System.arraycopy(args, 0, newArgs, 0, pos);
        if(args.length > pos)
        	System.arraycopy(args, pos, newArgs, pos +1, args.length - pos);
        return newArgs;
	}

	/***
	 *被迭代的Iterable对象元素作为参数的一部分迭代执行某方法，返回执行结果的数组
	 *@param seq  被迭代的对象
	 *@param f 执行的方法
	 *@param target 执行方法的对象
	 *@param v 返回值数组，当该数组的长度不够时，返回该类型的新的数组
	 *@param pos 被迭代的数组元素在参数表中的位置
	 *@param args 方法执行的参数表
	 *@return 执行结果数组，类型为参数v的类型。
	 ****/
	@SuppressWarnings("unchecked")
	public static <T extends Iterable,V> V[] each(T seq,Method f,Object target,V[] v,int pos,Object... args){
		try{
			if(seq == null)return null;
			Object[] newArgs = parseArgs(args,pos);
	        Iterator itor = seq.iterator();
	        List<V> list = new ArrayList<V>();
			for(int i=0;itor.hasNext();i++){
				newArgs[pos] = itor.next();
				list.add((V)f.invoke(target, newArgs));
			}
			return list.toArray(v);
		}catch(Exception e){
			throw new RuntimeException(e);
		}
	}

	/***
	 *判断某对象是否在数组中
	 *@param seq  目标数组
	 *@param arg 要判断的对象
	 *@return boolean
	 ****/
	public static <T> boolean any(T[] seq,Object arg){
		return indexOf(seq,arg) != -1;
	}
	
	/***
	 *被迭代的数组元素作为执行目标迭代执行方法，判断是否有一个返回结果为true
	 *@param seq  目标数组
	 *@param f  要执行的方法
	 *@param args 执行方法的参数表
	 *@return boolean
	 ****/
	public static <T> boolean any(T[] seq,Method f,Object... args){
		return indexOf(seq,f,args) != -1;
	}
	
	/***
	 *查找某对象在数组中的位置
	 *@param seq  目标数组
	 *@param arg 要判断的对象
	 *@return int 位置。当数组中不存在该对象时返回 -1;
	 ****/
	public static <T> int indexOf(T[] seq,Object arg){
		if(seq == null)return -1;
		for(int i =0;i<seq.length;i++)
			if(seq[i] == arg || arg.equals(seq[i]))return i;
		return -1;
	}
	
	/***
	 *被迭代的数组元素作为执行目标迭代执行方法，查找返回结果为true的元素的位置
	 *@param seq  目标数组
	 *@param f  要执行的方法
	 *@param args 执行方法的参数表
	 *@return int 位置。都不返回true时返回 -1;
	 ****/
	public static <T> int indexOf(T[] seq,Method f,Object... args){
		if(seq == null || f.getReturnType() != boolean.class)return -1;
		try{
			for(int i =0;i<seq.length;i++)
				if((Boolean)f.invoke(seq[i], args))return i;
			return -1;
		}catch(Exception e){
			return -1;
		}
	}
	
	/***
	 *被迭代的Iterable对象元素作为执行目标迭代执行某方法，返回执行结果的数组
	 *@param seq  被迭代的Iterable对象
	 *@param f 执行的方法
	 *@param v 返回值数组，当该数组的长度不够时，返回该类型的新的数组
	 *@param args 方法执行的参数表
	 *@return 执行结果数组，类型为参数v的类型。
	 ****/
	public static <T,S extends Iterable<? extends T>,V> 
		V[] apply(S seq,Method f,V[] v,Object... args){
		try{
			if(seq == null)return null;
			List<Object> res = new ArrayList<Object>();
			for(T t:seq)res.add(f.invoke(t, args));
			return res.toArray(v);
		}catch(Exception e){
			throw new RuntimeException(e);
		}
	}

	/***
	 *判断某对象是否在Iterable对象中存在
	 *@param seq  目标Iterable对象
	 *@param arg 要判断的对象
	 *@return boolean;
	 ****/
	public static <T,S extends Iterable<? extends T>> boolean any(S seq,Object arg){
		boolean res = false;
		if(seq == null)return false;
		for(T t:seq)if(t == arg || arg.equals(t))return true;
		return res;
	}
	
	/***
	 *被迭代的Iterable对象元素作为执行目标迭代执行方法，判断是否有一个返回结果为true
	 *@param seq  目标Iterable对象
	 *@param f  要执行的方法
	 *@param args 执行方法的参数表
	 *@return boolean
	 ****/
	public static <T,S extends Iterable<? extends T>> 
		boolean any(S seq,Method f,Object... args){
		boolean res = false;
		if(seq == null || f.getReturnType() != boolean.class)return false;
		try{
			for(T t:seq)
				if((Boolean)f.invoke(t, args))return true;
		}catch(Exception e){
			return false;
		}
		return res;
	}
	
}
